home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Applications / Fixation 1.3 / tcpstuff.c < prev    next >
Text File  |  1996-04-02  |  25KB  |  915 lines

  1. // tcpstuff.cpp
  2. // most copyright John Norstad
  3.  
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include <ctype.h>
  7. #include <stdio.h>
  8.  
  9. #include "mytypes.h"
  10. #include "MyMacTCP.h"
  11.  
  12. #include "error.h"
  13. #include "util.h"
  14. #include "tcpstuff.h"
  15. #include "globals.h"
  16. #include "preffile.h"
  17.  
  18. /*    Types. */
  19.  
  20. typedef struct TStream {            /* Stream info */
  21.  
  22.     TCPiopb pBlock;                    /* MacTCP parameter block (must be first, unused with
  23.                                        Open Transport) */
  24.     
  25.     unsigned long serverAddr;        /* IP address of server */
  26.     unsigned short serverPort;        /* port number on server */
  27.     unsigned short localPort;        /* local port number */
  28. //    CStr255 command;                /* last command sent on stream */
  29. //    CStr255 response;                /* last response received on stream */
  30.     long responseCode;                /* last response code received on stream */
  31.     Boolean closing;                /* true when closing stream */
  32.     Boolean otherSideHasClosed;        /* true when other side has closed its end of 
  33.                                        the stream */
  34.     Boolean weHaveClosed;            /* true when we have closed our end of the stream */
  35.     Boolean release;                /* true when stream should be released */
  36.     long bytesIn;                    /* number of bytes received on stream */
  37.     long bytesOut;                    /* number of bytes sent on stream */
  38.     
  39.     short myID;
  40.     
  41.     /* Fields used only with MacTCP. */
  42.     
  43.     long myA5;                        /* our A5 register */
  44.     StreamPtr tcpStream;            /* MacTCP stream pointer */
  45.     struct wdsEntry wds[2];            /* MacTCP write data structure */
  46.     char mactcpBuf[1];                /* MacTCP buffer - size depends on MTU (must be last) */
  47.  
  48. } TStream, *TStreamPtr;
  49.  
  50.     // defines for sending data
  51. enum {
  52.     kNumSmallOut = 8,
  53.     kNumMidOut = 2,
  54.     kNumLargeOut = 2,
  55.     kNumOutChunks = kNumSmallOut + kNumMidOut + kNumLargeOut,
  56.     
  57.     kSmallOutSize = 24,
  58.     kMidOutSize = 128,
  59.     kLargeOutSize = 2048
  60. };
  61.  
  62. typedef struct {
  63.     TCPiopb pBlock;
  64.     struct wdsEntry wds[2];            /* MacTCP write data structure */
  65.     short bufSize;
  66.     uchar buf[2];        // variable size
  67. } OutChunk;
  68.  
  69. OutChunk *outChunk[kNumOutChunks];
  70.     
  71. static short gRefNum;                    /* MacTCP driver reference number */
  72. static long gStreamBufSize;                /* stream buffer size */
  73. static long gTCPBufSize;                /* TCP buffer size for MacTCP */
  74. static UniversalProcPtr gOldExitToShellUPP;
  75. static UniversalProcPtr gMyExitToShellUPP;
  76. static ResultUPP gMacTCPDNRResultProcUPP = nil;
  77. static TCPIOCompletionUPP gMacTCPCloseStreamCompletionRoutineUPP = nil;
  78. static Boolean gMacTCPDNROperationInProgress = false;
  79.  
  80. unsigned long gMyAddress;
  81.  
  82. unsigned char buf[kMaxStreams][kBufferLength];
  83. long bufdata[kMaxStreams];
  84. TStream *myStream[kMaxStreams];
  85. short nexStatus[kMaxStreams];
  86.  
  87. /*----------------------------------------------------------------------------
  88.     NewStreamBuffer 
  89.     
  90.     Allocate a stream buffer.
  91.     
  92.     Exit:    function result = error code.
  93.             *s = pointer to new stream buffer.
  94. ----------------------------------------------------------------------------*/
  95.  
  96. static TStreamPtr NewStreamBuffer (void)
  97. {
  98.     OSErr err = noErr;
  99.     TStreamPtr s;
  100.  
  101.     s = (TStreamPtr) NewPtr(gStreamBufSize);
  102.     if (!s) return nil;
  103.     memset(s, 0, sizeof(TStream));
  104.     s->myA5 = SetCurrentA5();
  105.     return s;
  106. }
  107.  
  108.  
  109. /*----------------------------------------------------------------------------
  110.     InitMacTCPParamBlock 
  111.     
  112.     Initialize a MacTCP parameter block.
  113.     
  114.     Entry:    pBlock = pointer to parameter block.
  115.             csCode = MacTCP control code (TCPCreate, etc.).
  116. ----------------------------------------------------------------------------*/
  117.  
  118. static void InitMacTCPParamBlock (TCPiopb *pBlock, short csCode)
  119. {
  120.     memset(pBlock, 0, sizeof(TCPiopb));
  121.     pBlock->ioResult = 1;
  122.     pBlock->ioCRefNum = gRefNum;
  123.     pBlock->csCode = csCode;
  124. }
  125.  
  126.  
  127. /*----------------------------------------------------------------------------
  128.     CallMacTCP 
  129.     
  130.     Call MacTCP and wait for the call to complete.
  131.     
  132.     Entry:    s = pointer to stream.
  133.             returnImmediatelyOnError = true to return immediately if
  134.                 the GiveTime function returns an error.
  135.     
  136.     Exit:    function result = error code.
  137. ----------------------------------------------------------------------------*/
  138.  
  139. static OSErr CallMacTCP (TStreamPtr s, Boolean returnImmediatelyOnError)
  140. {
  141.     OSErr err = noErr, giveTimeErr = noErr;
  142.  
  143.     PBControlAsync((ParmBlkPtr)&s->pBlock);
  144.     do {
  145.     //    giveTimeErr = (*gGiveTime)();
  146.     //    if (err == noErr) err = giveTimeErr;
  147.     //    if (err != noErr && returnImmediatelyOnError) return err;
  148.     } while (s->pBlock.ioResult > 0);
  149.     err = s->pBlock.ioResult;
  150. //    if (err == connectionClosing || err == connectionDoesntExist ||
  151. //        err == connectionTerminated) s->otherSideHasClosed = true;
  152.     return err;
  153. }
  154.  
  155. static inline void CallMacTCPAsynch(TCPiopb *pBlock)
  156. {
  157.     PBControlAsync((ParmBlkPtr)pBlock);
  158. }
  159.  
  160.  
  161. /*----------------------------------------------------------------------------
  162.     MacTCPDNRResultProc 
  163.     
  164.     MacTCP domain name resolver completion routine.
  165.     
  166.     Entry:     hInfoPtr = pointer to hostInfo struct.
  167.             userDataPtr = pointer to user data.
  168. ----------------------------------------------------------------------------*/
  169.  
  170. static pascal void MacTCPDNRResultProc (struct hostInfo *hInfoPtr, char *userDataPtr)
  171. {
  172.     *(Boolean*)userDataPtr = true;
  173. }
  174.  
  175. /*----------------------------------------------------------------------------
  176.     MacTCPCloseStreamCompletionRoutine
  177.     
  178.     This is the asynchronous MacTCP completion routine used to close streams.
  179.     
  180.     This completion routine chains to itself to do the following tasks
  181.     involved in gracefully tearing down a stream in the background:
  182.     
  183.     Wait for QUIT command send to complete (the send is initiated by the
  184.         NetClose function below).
  185.     Read incoming data until an error occurs (signalling that the
  186.         server has closed its end of the connection).
  187.     Close our end of the connection.
  188.     
  189.     Entry:    pBlock = pointer to MacTCP parameter block.
  190. ----------------------------------------------------------------------------*/
  191.  
  192. static void MacTCPCloseStreamCompletionRoutine (TCPiopb *pBlock)
  193. {
  194.     TStreamPtr s;
  195.     OSErr err = noErr;
  196.     long savedA5;
  197.  
  198.     s = (TStreamPtr)pBlock;
  199.     
  200.     savedA5 = SetA5(s->myA5);
  201.     
  202.     if (s->pBlock.csCode == TCPSend) {
  203.     
  204.         /* The QUIT command has been sent. Start the first receive. */
  205.         
  206.            err = s->pBlock.ioResult;
  207.         if (err != noErr) {
  208.             s->release = true;
  209.             SetA5(savedA5);
  210.             return;
  211.         }
  212.         InitMacTCPParamBlock(&s->pBlock, TCPRcv);
  213.         s->pBlock.csParam.receive.rcvBuff = (Ptr) buf[s->myID];
  214.         s->pBlock.csParam.receive.rcvBuffLen = kBufferLength;
  215.     
  216.     } else if (s->pBlock.csCode == TCPRcv) {
  217.     
  218.         /* A receive operation has finished. If there was no error, start another
  219.            receive. If an error occurred, it was because the server has closed
  220.            its side of the connection. In this case, if we have already closed
  221.            our side of the connection, set the "release" flag to signal that
  222.            we can now release the stream and dispose of the queue element. If
  223.            we have not yet closed our side, we start the TCPClose. */
  224.        
  225.            err = s->pBlock.ioResult;
  226.            if (err == noErr) {
  227.                InitMacTCPParamBlock(&s->pBlock, TCPRcv);
  228.             s->pBlock.csParam.receive.rcvBuff = (Ptr) buf[s->myID];
  229.             s->pBlock.csParam.receive.rcvBuffLen = kBufferLength;
  230.         } else {
  231.             s->otherSideHasClosed = true;
  232.             if (s->weHaveClosed) {
  233.                 s->release = true;
  234.                 SetA5(savedA5);
  235.                 return;
  236.             } else {
  237.                 InitMacTCPParamBlock(&s->pBlock, TCPClose);
  238.             }
  239.         }
  240.     
  241.     } else if (s->pBlock.csCode == TCPClose) {
  242.     
  243.         /* Our close has finished. If the other side has also closed,
  244.            set the "release" flag to signal that we can now release
  245.            the stream and dispose of the queue element. If the other
  246.            side has not yet closed, issue a receive operation and wait
  247.            for the other side to close. */
  248.  
  249.         s->weHaveClosed = true;
  250.         if (s->otherSideHasClosed) {
  251.             s->release = true;
  252.             SetA5(savedA5);
  253.             return;
  254.         } else {
  255.             InitMacTCPParamBlock(&s->pBlock, TCPRcv);
  256.             s->pBlock.csParam.receive.rcvBuff = (Ptr) buf[s->myID];
  257.             s->pBlock.csParam.receive.rcvBuffLen = kBufferLength;
  258.         }
  259.                     
  260.     }
  261.     
  262.     /* Issue the next PBControl call in the chain. */
  263.  
  264.     s->pBlock.ioCompletion = gMacTCPCloseStreamCompletionRoutineUPP;
  265.     s->pBlock.tcpStream = s->tcpStream;
  266.     s->pBlock.ioResult = 1;
  267.     err = PBControlAsync((ParmBlkPtr)&s->pBlock);
  268.     if (err != noErr) s->release = true;
  269.      SetA5(savedA5);
  270.     
  271. }
  272.  
  273.  
  274. /*----------------------------------------------------------------------------
  275.     NetGetMyAddr 
  276.     
  277.     Get this Mac's IP address.
  278.     
  279.     Exit:    function result = error code.
  280.             *addr = the IP address of this Mac.
  281.             
  282.     With Open Transport, if the Mac has more than one IP interface, the
  283.     IP address of the default interface is returned.
  284. ----------------------------------------------------------------------------*/
  285.  
  286. static OSErr NetGetMyAddr (unsigned long *addr)
  287. {
  288.     struct GetAddrParamBlock pBlock;
  289.     OSErr err = noErr, giveTimeErr = noErr;
  290.     static Boolean gotIt = false;
  291.     static unsigned long myAddr;
  292.     
  293.     if (!gotIt) {
  294.     
  295.         memset(&pBlock, 0, sizeof(pBlock));
  296.         pBlock.ioResult = 1;
  297.         pBlock.csCode = ipctlGetAddr;
  298.         pBlock.ioCRefNum = gRefNum;
  299.         PBControlAsync((ParmBlkPtr)&pBlock);
  300.         while (pBlock.ioResult > 0) {
  301.     //        giveTimeErr = (*gGiveTime)();
  302.             if (err == noErr) err = giveTimeErr;
  303.         }
  304.         if (err != noErr) return err;
  305.         err = pBlock.ioResult;
  306.         if (err != noErr) return err;
  307.         myAddr = pBlock.ourAddress;
  308.         
  309.         
  310.         gotIt = true;
  311.     }
  312.     
  313.     *addr = myAddr;
  314.     return noErr;
  315. }
  316.  
  317. /*----------------------------------------------------------------------------
  318.     GetMaxTCPMTU 
  319.     
  320.     Get the max MTU size.
  321.     
  322.     Exit:    function result = max MTU, or 0 if error.
  323. ----------------------------------------------------------------------------*/
  324.  
  325. static long GetMaxTCPMTU (void)
  326. {
  327.     UDPiopb iopb;
  328.     OSErr err = noErr;
  329.     
  330.     memset(&iopb, 0, sizeof(iopb));
  331.     err = NetGetMyAddr(&iopb.csParam.mtu.remoteHost);
  332.     if (err != noErr) return 0;
  333.     iopb.ioCRefNum = gRefNum;
  334.     iopb.csCode = UDPMaxMTUSize;
  335.     err = PBControlSync((ParmBlkPtr)&iopb);
  336.     if (err != noErr) return 0;
  337.     return iopb.csParam.mtu.mtuSize;
  338. }
  339.  
  340.  
  341. /*----------------------------------------------------------------------------
  342.     DoTCPCreate 
  343.     
  344.     Create a stream.
  345.     
  346.     Entry:    s = pointer to stream.
  347.     
  348.     Exit:    function result = error code.
  349. ----------------------------------------------------------------------------*/
  350.  
  351. static OSErr DoTCPCreate (TStreamPtr s)
  352. {
  353.     OSErr err = noErr;
  354.  
  355.     InitMacTCPParamBlock(&s->pBlock, TCPCreate);
  356.     s->pBlock.csParam.create.rcvBuff = s->mactcpBuf;
  357.     s->pBlock.csParam.create.rcvBuffLen = gTCPBufSize;
  358.     err = CallMacTCP(s, false);
  359.     if (err != noErr) return err;
  360.     s->tcpStream = s->pBlock.tcpStream;
  361.     return noErr;
  362. }
  363.  
  364. /*----------------------------------------------------------------------------
  365.     DoTCPRelease 
  366.     
  367.     Release a stream.
  368.     
  369.     Entry:    s = pointer to stream.
  370.     
  371.     Exit:    function result = error code.
  372.     
  373.     Any active connection is also aborted, if necessary, before releasing 
  374.     the stream.
  375.     
  376.     With MacTCP, the function uses its own TCPiopb parameter block instead 
  377.     of the one inside the stream block, because the one inside the stream block
  378.     may already be in use by some other asynchronous operation.
  379. ----------------------------------------------------------------------------*/
  380.  
  381. static OSErr DoTCPRelease (short stream)
  382. {
  383.     TCPiopb pBlock;
  384.     OSErr err = noErr, giveTimeErr = noErr;
  385.     Boolean abort;
  386.     TStreamPtr s;
  387.  
  388.     s = myStream[stream];
  389.     if (!s || !s->tcpStream) return noErr;
  390.     InitMacTCPParamBlock(&pBlock, TCPRelease);
  391.     pBlock.tcpStream = s->tcpStream;
  392.     PBControlAsync((ParmBlkPtr)&pBlock);
  393.     while (pBlock.ioResult > 0) {
  394.     //    giveTimeErr = (*gGiveTime)();
  395.     //    if (err == noErr) err = giveTimeErr;
  396.     }
  397.     if (err == noErr) err = pBlock.ioResult;
  398.     if (err == noErr) {
  399.         s->tcpStream = 0;        // we know we're done with it
  400.         nexStatus[stream] = kStatClosed;
  401.     }
  402.     return err;
  403. }
  404.  
  405.  
  406.  
  407. /*----------------------------------------------------------------------------
  408.     DoTCPActiveOpen 
  409.     
  410.     Open an active stream.
  411.     
  412.     Entry:    s = pointer to stream.
  413.             addr = IP address of server.
  414.             port = port number of service.
  415.     
  416.     Exit:    function result = error code.
  417. ----------------------------------------------------------------------------*/
  418.  
  419. OSErr DoTCPActiveOpen (short stream, unsigned long addr, 
  420.     unsigned short port)
  421. {
  422.     OSErr err = noErr;
  423.     TStreamPtr s = myStream[stream];
  424.     
  425.     InitMacTCPParamBlock(&s->pBlock, TCPActiveOpen);
  426.     s->pBlock.tcpStream = s->tcpStream;
  427.     s->pBlock.csParam.open.remoteHost = addr;
  428.     s->pBlock.csParam.open.remotePort = port;
  429.     err = CallMacTCP(s, true);
  430.     if (err == noErr)
  431.         s->localPort = s->pBlock.csParam.open.localPort;
  432.     return err;
  433. }
  434.  
  435.  
  436. /*----------------------------------------------------------------------------
  437.     DoTCPPassiveOpen 
  438.     
  439.     Open a passive stream.
  440.     
  441.     Entry:    s = pointer to stream.
  442.     
  443.     Exit:    function result = error code.
  444.             *port = assigned unused local port number.
  445.             
  446.     Note: Unlike the other "DoTCPxxx" functions, DoTCPPassiveOpen is
  447.     asynchronous. The passive stream is opened, but the function does not
  448.     wait for another host to connect. The function is used by 
  449.     NetFTPDataPassiveOpen to open passive FTP data streams. The caller must 
  450.     call NetFTPDataWaitForConnection to wait for the FTP server to connect
  451.     to the stream.
  452. ----------------------------------------------------------------------------*/
  453.  
  454. OSErr DoTCPPassiveOpen (short stream, unsigned short *port)
  455. {
  456.     OSErr err = noErr;
  457.     TStreamPtr s = myStream[stream];
  458.  
  459.     InitMacTCPParamBlock(&s->pBlock, TCPPassiveOpen);
  460.     s->pBlock.tcpStream = s->tcpStream;
  461.     s->pBlock.csParam.open.localPort = *port;
  462.     PBControlAsync((ParmBlkPtr)&s->pBlock);
  463.     while (s->pBlock.csParam.open.localPort == 0) {
  464.     //    err = (*gGiveTime)();
  465.     //    if (err != noErr) return err;
  466.     }
  467.     *port = s->localPort = s->pBlock.csParam.open.localPort;
  468.     return noErr;
  469. }
  470.  
  471.  
  472. /*----------------------------------------------------------------------------
  473.     DoTCPSend 
  474.     
  475.     Send data on a stream.
  476.     
  477.     Entry:    s = pointer to stream.
  478.             data = pointer to data to send.
  479.             len = length of data to send.
  480.             push = true to set push data flag. This flag should be set on
  481.                 the last buffer of data being sent on the stream before
  482.                 a response from the server is expected. This flag is need
  483.                 to keep IBM VM/CMS happy. (Note OT handles this internally,
  484.                 so this is needed only with MacTCP.)
  485.     
  486.     Exit:    function result = error code.
  487. ----------------------------------------------------------------------------*/
  488.  
  489. static OSErr OldDoTCPSend (TStreamPtr s, void *data, unsigned short len, Boolean push)
  490. {
  491.     OSErr err = noErr;
  492. //    TCPiopb pBlock;
  493.     
  494.     s->wds[0].ptr = (Ptr) data;
  495.     s->wds[0].length = len;
  496.     InitMacTCPParamBlock(&s->pBlock, TCPSend);
  497.     s->pBlock.tcpStream = s->tcpStream;
  498.     s->pBlock.csParam.send.wdsPtr = (Ptr)s->wds;
  499.     s->pBlock.csParam.send.pushFlag = push;
  500.     err = CallMacTCP(s, true);
  501.     return err;    
  502. }
  503.  
  504. static OSErr DoTCPSend (TStreamPtr s, void *data, unsigned short len, Boolean push)
  505. {
  506.     OSErr err = noErr;
  507.     short nnn;
  508.     
  509.     for (nnn=0;nnn<kNumOutChunks;nnn++) {
  510.         OutChunk *oc = outChunk[nnn];
  511.         verify(oc);
  512.         if (oc->bufSize < len)
  513.             continue;
  514.         if (oc->pBlock.ioResult > 0)
  515.             continue;        // already being used
  516.             
  517.             // okay, I think we're ready to use it and send
  518.         oc->wds[0].ptr = (Ptr) oc->buf;
  519.         oc->wds[0].length = len;
  520.         memcpy(oc->buf, data, len);
  521.         InitMacTCPParamBlock(&oc->pBlock, TCPSend);
  522.         oc->pBlock.tcpStream = s->tcpStream;
  523.         oc->pBlock.csParam.send.wdsPtr = (Ptr)oc->wds;
  524.         oc->pBlock.csParam.send.pushFlag = push;
  525.         CallMacTCPAsynch(&oc->pBlock);
  526.         return noErr;
  527.     }
  528.     tprintf("Error writing data: no available buffers!\r");
  529.     return -1;
  530. }
  531.  
  532. OSErr
  533. SendData(short stream, void *data, long length)
  534. {
  535.     OSErr err;
  536.     
  537.     if (length == 0)
  538.         return noErr;
  539.         
  540.     if (nexStatus[stream] != kStatOpen)
  541.         return -1;
  542.     
  543.     if (err = DoTCPSend(myStream[stream], data, length, true))
  544.         VDebugStr("Error writing data!");        
  545.     return err;
  546. }
  547.  
  548. /*----------------------------------------------------------------------------
  549.     DoTCPRcv 
  550.     
  551.     Reveive data on a stream.
  552.     
  553.     Entry:    s = pointer to stream.
  554.             data = pointer to data buffer.
  555.             *len = length of data buffer.
  556.     
  557.     Exit:    function result = error code.
  558.             *len = number of bytes received.
  559. ----------------------------------------------------------------------------*/
  560.  
  561. static OSErr DoTCPRcv (TStreamPtr s, Ptr data, unsigned short *len)
  562. {
  563.     OSErr err = noErr;
  564.     
  565.     InitMacTCPParamBlock(&s->pBlock, TCPRcv);
  566.     s->pBlock.tcpStream = s->tcpStream;
  567.     s->pBlock.csParam.receive.rcvBuff = StripAddress(data);
  568.     s->pBlock.csParam.receive.rcvBuffLen = *len;
  569.     err = CallMacTCP(s, true);
  570.     *len = s->pBlock.csParam.receive.rcvBuffLen;
  571.     if (err == noErr) s->bytesIn += *len;
  572.     return err;
  573. }
  574.  
  575. void ReleaseStreams(void)
  576. {
  577.     short nnn;
  578.     for (nnn=0;nnn<kMaxStreams;nnn++)
  579.         if (myStream[nnn] != nil && myStream[nnn]->tcpStream != nil)
  580.             DoTCPRelease(nnn);
  581. }
  582.  
  583. OSErr
  584. PrepareTheWay(short stream)
  585. {
  586.     OSErr err;
  587.     
  588.     if (err = DoTCPCreate(myStream[stream]))
  589.         VDebugStr("Error on create: stream %d", stream);
  590.     return err;
  591. }
  592.  
  593. /*----------------------------------------------------------------------------
  594.     MyExitToShell 
  595.     
  596.     ExitToShell trap patch (for MacTCP only).
  597.     
  598.     This patch makes sure that all open streams are closed when ExitToShell
  599.     is called (e.g., if the program crashes and you type "es" in MacsBug, or
  600.     if you use Command-Option-Escape to force quit the program). This keeps 
  601.     MacTCP happy. It doesn't always work, but it helps sometimes.
  602.     
  603.     Open Transport has its own mechanisms for doing this, so this patch
  604.     is only installed if we are using MacTCP.
  605. ----------------------------------------------------------------------------*/
  606.  
  607. static void MyExitToShell (void)
  608. {
  609.     SetCurrentA5();
  610.     SetToolTrapAddress(gOldExitToShellUPP, _ExitToShell);
  611.     ReleaseStreams();
  612.     ExitToShell();
  613. }
  614.  
  615.  
  616.  
  617. /*----------------------------------------------------------------------------
  618.     PatchExitToShell 
  619.     
  620.     Install a patch on the ExitToShell trap (for MacTCP only).
  621. ----------------------------------------------------------------------------*/
  622.  
  623. static void PatchExitToShell (void)
  624. {
  625.     gOldExitToShellUPP = GetToolTrapAddress(_ExitToShell);
  626.     gMyExitToShellUPP = 
  627.         NewRoutineDescriptor((ProcPtr)MyExitToShell, kPascalStackBased, GetCurrentISA());
  628.     SetToolTrapAddress(gMyExitToShellUPP, _ExitToShell);
  629. }
  630.  
  631. static void
  632. InitOutChunks(void)
  633. {
  634.     short nnn, sz, bsize;
  635.     
  636.     for (nnn=0;nnn<kNumOutChunks;nnn++) {
  637.         if (nnn<kNumSmallOut)
  638.             bsize = kSmallOutSize;
  639.         else if (nnn<kNumMidOut)
  640.             bsize = kMidOutSize;
  641.         else
  642.             bsize = kLargeOutSize;
  643.         sz = bsize + sizeof(OutChunk);
  644.         sz -= 2;        // important bytes
  645.         
  646.         outChunk[nnn] = (OutChunk *) NewPtr(sz);
  647.         verify(outChunk[nnn]);
  648.         
  649.         memset(outChunk[nnn], 0, sz);
  650.         
  651.         outChunk[nnn]->bufSize = bsize;
  652.     }
  653.     
  654. }
  655.  
  656.  
  657. OSErr NetInit (void)
  658. {
  659.     short i;
  660.     OSErr err = noErr;
  661.     long mtu;
  662.  
  663.     
  664.     gMacTCPDNRResultProcUPP = NewResultProc(MacTCPDNRResultProc);
  665.     gMacTCPCloseStreamCompletionRoutineUPP = 
  666.         NewTCPIOCompletionProc(MacTCPCloseStreamCompletionRoutine);
  667.     err = OpenDriver("\p.IPP", &gRefNum);
  668.     if (err != noErr) return err;
  669.     mtu = GetMaxTCPMTU();
  670.     gTCPBufSize = 8 * mtu;
  671.     if (gTCPBufSize < kMinTCPBufSize) gTCPBufSize = kMinTCPBufSize;
  672.     gStreamBufSize = sizeof(TStream) - 1 + gTCPBufSize;
  673. //    PatchExitToShell();
  674.     
  675.     for (i = 0; i < kMaxStreams; i++) {
  676.         myStream[i] = NewStreamBuffer();
  677.         if (!myStream[i]) return -1;
  678.         myStream[i]->myID = i;
  679.         bufdata[i] = 0;
  680.     }
  681.     
  682.     if (err = NetGetMyAddr(&gMyAddress)) {
  683.         VDebugStr("Error getting my address.");
  684.         return err;
  685.     }
  686.  
  687.     InitOutChunks();
  688.     
  689.     return noErr;
  690. }
  691.  
  692. static OSErr
  693. GetConnectionStatus(TStreamPtr s)
  694. {
  695.     OSErr err = noErr;
  696.     
  697.     InitMacTCPParamBlock(&s->pBlock, TCPStatus);
  698.     s->pBlock.tcpStream = s->tcpStream;
  699.     err = CallMacTCP(s, true);
  700.     return err;
  701. }
  702.  
  703. #if TIMESTAMP
  704. long process_chars_from_server(char *buf, long len);
  705. #include "timeseal.h"
  706. #endif
  707.  
  708. static void
  709. Upkeep(void)
  710. {
  711.     short nnn;
  712.     TStreamPtr s;
  713.     unsigned long dat;
  714.     unsigned short rd;
  715.     short conn;
  716.     static short lastcon = -1;
  717.     unsigned char *dest;
  718.  
  719.     for (nnn=0;nnn<kMaxStreams;nnn++) {
  720.         s = myStream[nnn];
  721.         if (s->tcpStream)
  722.             if (!GetConnectionStatus(s)) {
  723.                     // do reading in stuff
  724.                 dat = s->pBlock.csParam.status.amtUnreadData;
  725.                 conn = s->pBlock.csParam.status.connectionState;
  726.             /*    if (conn != lastcon) {
  727.                     lastcon = conn;
  728.                     tprintf("\r#####%d####\r", conn);
  729.                 }*/
  730.                 rd = dat;
  731.                 if (rd > 0) {
  732.                         // don't read too many bytes
  733.                     if (bufdata[nnn] + rd > kBufferLength)
  734.                         rd = kBufferLength - bufdata[nnn];
  735.                     dest = &buf[nnn][bufdata[nnn]];
  736.                     if (DoTCPRcv(s, (Ptr) dest, &rd))
  737.                         VDebugStr("Error reading data.");
  738. #if TIMESTAMP
  739.                     if (gPrefs.serverType == kIcc && gPrefs.timeseal) {
  740.                         bufdata[nnn] += process_chars_from_server((char *) dest, rd);
  741.                     }
  742.                     else if (gPrefs.serverType == kFics && gPrefs.timeseal) {
  743.                         bufdata[nnn] += SealFromServer((char *) dest, rd);
  744.                     }
  745.                     else
  746. #endif
  747.                         bufdata[nnn] += rd;
  748.                 //    tprintf("Data: %u\r", rd);
  749.                     break;
  750.                 }
  751.                 
  752.                     // give rest of world some status on this connection
  753.                     // nice of Apple to provide these constants in the header
  754.                 switch (conn) {
  755.                     // next line handled better in Release
  756.             //        case 0: case 14: nexStatus[nnn] = kStatClosed; break;
  757.                     case 2: case 4: nexStatus[nnn] = kStatListening; break;
  758.                     case 8: nexStatus[nnn] = kStatOpen; break;
  759.                     default: nexStatus[nnn] = kStatOther; break;
  760.                 }
  761.                 
  762.                     // check for closed connection
  763.                     // it seems to hang on 14, so why not close it (???)
  764.                 if (conn == 0 || conn == 14) {
  765.                     if (!DoTCPRelease(nnn))
  766.                         tprintf("Connection terminated\r");
  767.                 }
  768.             }
  769.             else {
  770.             //    VDebugStr("Error getting connection status stream %d", nnn);
  771.                     // somehow this connection closed without us knowing
  772.                 nexStatus[nnn] = kStatClosed;
  773.                 DoTCPRelease(nnn);        // ???
  774.             }
  775.     }
  776. }
  777.  
  778. OSErr NetIdle (void)
  779. {
  780.     TStreamPtr s, nextClose, prev = nil;
  781.     OSErr err = noErr;
  782.     short nnn;
  783.  
  784.     for (nnn=0;nnn<kMaxStreams;nnn++) {
  785.         s = myStream[nnn];
  786.         if (s->release) {
  787.             err = DoTCPRelease(nnn);
  788.         //    DisposeStreamBuffer(s);
  789.         }
  790.     }
  791.     
  792.     Upkeep();
  793.     
  794.     return noErr;
  795. }
  796.  
  797. /*----------------------------------------------------------------------------
  798.     NetNameToAddr 
  799.     
  800.     Translate a domain name to an IP address.
  801.     
  802.     Entry:     name = C-format domain name string, optionally followed by a
  803.                 comma, space, or colon and then the port number.
  804.             defaultPort = default port number.
  805.     
  806.     Exit:    function result = error code.
  807.             *addr = IP address.
  808.             *port = port number.
  809. ----------------------------------------------------------------------------*/
  810.  
  811. OSErr NetNameToAddr (char *name,
  812.     unsigned long *addr, unsigned short *port)
  813. {
  814.     OSErr err = noErr, giveTimeErr = noErr;
  815.     short i;
  816.     struct hostInfo hInfoMacTCP;
  817.     Boolean done = false;
  818.     char domainName[256];
  819.     char *p, *q;
  820.     
  821.     p = name;
  822.     q = domainName;
  823.     while (*p != 0) *q++ = *p++;
  824.     *q = 0;
  825. /*    while (*p != 0 && *p != ',' && *p != ' ' && *p != ':') *q++ = *p++;
  826.     *q = 0;
  827.     q = p;
  828.     while (*q == ' ') q++;
  829.     if (*q == 0) {
  830.         *port = defaultPort;
  831.     } else {
  832.         p++;
  833.         if (!isdigit(*p)) return -1;
  834.         q = p+1;
  835.         while (isdigit(*q)) q++;
  836.         while (*q == ' ') q++;
  837.         if (*q != 0) return -1;
  838.         *port = atoi(p);
  839.     }
  840. */
  841.     
  842.     while (gMacTCPDNROperationInProgress) {
  843.         /* Some other thread is using the DNR. Wait for it to finish. */
  844.     //    err = (*gGiveTime)();
  845.     //    if (err != noErr) return err;
  846.     }
  847.     err = OpenResolver(nil);
  848.     if (err != noErr) return err;
  849.     memset(&hInfoMacTCP, 0, sizeof(hInfoMacTCP));
  850.     gMacTCPDNROperationInProgress = true;
  851.     err = StrToAddr(domainName, &hInfoMacTCP, gMacTCPDNRResultProcUPP, (char*)&done);
  852.     if (err == cacheFault) {
  853.         err = noErr;
  854.         while (!done) {
  855.         //    giveTimeErr = (*gGiveTime)();
  856.         //    if (err == noErr) err = giveTimeErr;
  857.         }
  858.         if (err == noErr) err = hInfoMacTCP.rtnCode;
  859.     }
  860.     gMacTCPDNROperationInProgress = false;
  861. //    (*gGiveTime)();
  862.     CloseResolver();
  863.     if (err != noErr) return err;
  864.     *addr = hInfoMacTCP.addr[0];
  865.     
  866.     return noErr;
  867. }
  868.  
  869.  
  870. /*----------------------------------------------------------------------------
  871.     NetAddrToName 
  872.     
  873.     Translate an IP address to a domain name.
  874.     
  875.     Entry:    addr = IP address.
  876.     
  877.     Exit:    function result = error code.
  878.             name = domain name, as a C-format string.
  879. ----------------------------------------------------------------------------*/
  880.  
  881. OSErr NetAddrToName (unsigned long addr, char *name)
  882. {
  883.     struct hostInfo hInfoMacTCP;
  884.     OSErr err = noErr, giveTimeErr = noErr;
  885.     Boolean done=false;
  886.     
  887.     while (gMacTCPDNROperationInProgress) {
  888.         /* Some other thread is using the DNR. Wait for it to finish. */
  889.     //    err = (*gGiveTime)();
  890.     //    if (err != noErr) return err;
  891.     }
  892.     
  893.     err = OpenResolver(nil);
  894.     if (err != noErr) return err;
  895.     memset(&hInfoMacTCP, 0, sizeof(hInfoMacTCP));
  896.     
  897.     gMacTCPDNROperationInProgress = true;
  898.     err = AddrToName(addr, &hInfoMacTCP, gMacTCPDNRResultProcUPP, (char*)&done);
  899.     if (err == cacheFault) {
  900.         err = noErr;
  901.         while (!done) {
  902.     //        giveTimeErr = (*gGiveTime)();
  903.     //        if (err == noErr) err = giveTimeErr;
  904.         }
  905.         if (err == noErr) err = hInfoMacTCP.rtnCode;
  906.     }
  907.     gMacTCPDNROperationInProgress = false;
  908. //    (*gGiveTime)();
  909.     CloseResolver();
  910.     if (err != noErr) return err;
  911.     hInfoMacTCP.cname[254] = 0;
  912.     strcpy(name, hInfoMacTCP.cname);
  913.     return noErr;
  914. }
  915.